#include "ConnectionPool.h"

ConnectionPool *ConnectionPool::getConnectionPool()
{
    static ConnectionPool pool;
    return &pool;
}

std::shared_ptr<Connection> ConnectionPool::getConnection()
{
    std::unique_lock<std::mutex> lock(_queueMutex);
    while(_connectQue.empty()){
        //条件变量等待超时时间
        if(std::cv_status::timeout == _cv.wait_for(lock,std::chrono::microseconds(_connectionTimeout))){
            //若正常返回，说明超时
            if(_connectQue.empty()){
                std::cerr<<"get connection fail...timeout...."<<'\n';
                return nullptr;
            }
        }
    }
	// 这里自定义删除器是因为我们不是要真正删除，而是归还到queue当中
	std::shared_ptr<Connection> sp(_connectQue.front(),[&](Connection* pcon) {
		std::unique_lock<std::mutex> lock(_queueMutex);
		pcon->refreshAliveTime(); // 刷新一下开始空闲的起始时间
		_connectQue.push(pcon);
		});
	_connectQue.pop();
	_cv.notify_all();
	return sp;
}

ConnectionPool::~ConnectionPool()
{
    this->isRun = true;
    _cv.notify_all();
}

ConnectionPool::ConnectionPool()
{
    if(!loadConfigFile()){
        return;
    }

    //初始化一部分连接
    for(int i=0;i<this->_intiConnectSize;i++){
        Connection* p = new Connection();
        p->connect(_ip,_port,_username,_password,_dbname);
        p->refreshAliveTime();
        _connectQue.push(p);
        _connectCnt++;
        //开辟两个线程，一个用于连接生产者，一个用于扫描空闲区
        std::thread produce(std::bind(
            &ConnectionPool::produceConnectionTask,this
        ));
        produce.detach();
        std::thread scanner(std::bind(
            &ConnectionPool::scanConnectionTask,this
        ));
        scanner.detach();
        
    }
}

void ConnectionPool::produceConnectionTask()
{
    while(1){
        if(isRun){
            return;
        }
        std::unique_lock<std::mutex> lock(_queueMutex);
        while(!isRun && !_connectQue.empty()){
            if(isRun)
                return;
            _cv.wait(lock);
        }
        if(isRun && _connectCnt < _maxConnectSize){
            Connection* p = new Connection();
            p->connect(_ip,_port,_username,_password,_dbname);
            p->refreshAliveTime();
            _connectQue.push(p);
            _connectCnt++;
        }
        //通知消费者
        _cv.notify_all();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void ConnectionPool::scanConnectionTask()
{
    while(1){
        if(isRun){
            return;
        }
        std::unique_lock<std::mutex> lock(_queueMutex);
        while(_connectCnt > _intiConnectSize){
            if(isRun){
                return;
            }
            if(_connectQue.empty()){
                break;
            }
            Connection* p =_connectQue.front();
            if(p->getAliveTime() >= _maxIdletiom * 1000){
                _connectQue.pop();
                _connectCnt--;
                delete p;
            }else{
                break;
            }
        }
    }
}

bool ConnectionPool::loadConfigFile()
{
    _ip = "127.0.0.1";
    _port = 1478;
    _username = "root";
    _password = "123456";
    _dbname = "mysql";
    _intiConnectSize = 5000;   //初始连接数量
    _maxConnectSize = 10000;    //最大连接数量
    _maxIdletiom = 5;       //最大空闲时间
    _connectionTimeout = 5; //超时时间
    return true;
}
